package com.sunyzc.ebaotech.soap.simulator;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.cxf.endpoint.Client;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sunyzc.ebaotech.ybt.simulator.util.CodeUtil;
import com.sunyzc.ebaotech.ybt.simulator.util.IOUtil;
import com.sunyzc.ebaotech.ybt.simulator.util.PropertyUtil;

public abstract class AbstractSOAPProcessor implements ISOAPProcessor {
	private static final Logger log = LoggerFactory.getLogger(AbstractSOAPProcessor.class);
	private int dateOffSet = 0;
	private final static int BUFFER_SIZE = 16 * 1024;
	protected Map<String, String> transXmlMap = new HashMap<String, String>();

	@Override
	public String generateRequestBodyTemplateStr(String transType) throws Exception {
		String requestBodyContentStr = null;
		BufferedInputStream inputStream = null;
		ByteArrayOutputStream outputStream = null;
		try {
			inputStream = new BufferedInputStream(this.getClass().getResourceAsStream(transType + ".xml"));
			outputStream = new ByteArrayOutputStream();
			byte[] buffer = new byte[BUFFER_SIZE];
			int readLength = 0;
			while ((readLength = inputStream.read(buffer)) != -1)
				outputStream.write(buffer, 0, readLength);
			requestBodyContentStr = new String(outputStream.toByteArray());
			// --------------------------------------------处理报文----------------------------------------------
			requestBodyContentStr = requestBodyContentStr.replaceAll("<!-- （.*）.* -->", ""); // 去除报文中符合规则的注释，但不包含标准注释
			if (requestBodyContentStr.contains("@TRANS_CODE@"))
				requestBodyContentStr = requestBodyContentStr.replace("@TRANS_CODE@", "Sun" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new GregorianCalendar().getTime())); // 交易流水号

			if (requestBodyContentStr.contains("@APPLY_CODE@"))
				requestBodyContentStr = requestBodyContentStr.replace("@APPLY_CODE@", CodeUtil.generateCommonCode(PropertyUtil.getNexSerialNum(), "070")); // 网销（官网）投保单
			if (requestBodyContentStr.contains("@POLICY_CODE@"))
				requestBodyContentStr = requestBodyContentStr.replace("@POLICY_CODE@", CodeUtil.generateCommonCode(PropertyUtil.getNexSerialNum(), "092")); // 网销（官网）业务保单
			if (requestBodyContentStr.contains("@PRINT_CODE@"))
				requestBodyContentStr = requestBodyContentStr.replace("@PRINT_CODE@", PropertyUtil.getNextPrintCode()); // 印刷号
		} finally {
			IOUtil.closeQuietly(inputStream);
			IOUtil.closeQuietly(outputStream);
		}
		return requestBodyContentStr;
	}

	@Override
	public String generateRequestBodyBytes(String transType, String requestBodyTemplateStr) throws Exception {
		String requestBodyContentStr = (requestBodyTemplateStr != null && !requestBodyTemplateStr.trim().equals("")) ? requestBodyTemplateStr : generateRequestBodyTemplateStr(transType);
		requestBodyContentStr = requestBodyContentStr.replaceAll("<!-- （.*）.* -->", ""); // 去除报文中符合规则的注释，但不包含标准注释
		Calendar currentDateCalendar = new GregorianCalendar();
		currentDateCalendar.add(Calendar.DATE, dateOffSet);
		String currentDateTimeStr = new SimpleDateFormat(getDateFormatStr(transType)[0]).format(currentDateCalendar.getTime());
		String currentDateStr = new SimpleDateFormat(getDateFormatStr(transType)[1]).format(currentDateCalendar.getTime());
		String currentTimeStr = new SimpleDateFormat(getDateFormatStr(transType)[2]).format(currentDateCalendar.getTime());
		if (requestBodyContentStr.contains("@TRANS_CODE@"))
			requestBodyContentStr = requestBodyContentStr.replace("@TRANS_CODE@", "Sun" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new GregorianCalendar().getTime())); // 交易流水号，根据实际本地当前时间生成
		if (requestBodyContentStr.contains("@TRANS_DATE@"))
			requestBodyContentStr = requestBodyContentStr.replace("@TRANS_DATE@", currentDateStr); // 交易日期，服务器今日日期
		if (requestBodyContentStr.contains("@APPLY_DATE@"))
			requestBodyContentStr = requestBodyContentStr.replace("@APPLY_DATE@", currentDateStr); // 投保日期，服务器今日日期
		if (requestBodyContentStr.contains("@TRANS_TIME@"))
			requestBodyContentStr = requestBodyContentStr.replace("@TRANS_TIME@", currentTimeStr); // 交易时间，本地当前时间
		if (requestBodyContentStr.contains("@TRANS_DATE_TIME@"))
			requestBodyContentStr = requestBodyContentStr.replace("@TRANS_DATE_TIME@", currentDateTimeStr); // 交易日期和时间，服务器今日日期和本地当前时间
		if (requestBodyContentStr.contains("@EFFECT_DATE@")) {
			Calendar effectDateCalendar = new GregorianCalendar();
			effectDateCalendar.setTime(currentDateCalendar.getTime());
			effectDateCalendar.add(Calendar.DATE, 1); // 设置生效日期为投保日期的次日
			String effectDateStr = new SimpleDateFormat(getDateFormatStr(transType)[1]).format(effectDateCalendar.getTime());
			requestBodyContentStr = requestBodyContentStr.replace("@EFFECT_DATE@", effectDateStr);
		}
		if (requestBodyContentStr.contains("@APPLY_CODE@"))
			requestBodyContentStr = requestBodyContentStr.replace("@APPLY_CODE@", CodeUtil.generateCommonCode(PropertyUtil.getNexSerialNum(), "070")); // 网销（官网）投保单
		if (requestBodyContentStr.contains("@POLICY_CODE@"))
			requestBodyContentStr = requestBodyContentStr.replace("@POLICY_CODE@", CodeUtil.generateCommonCode(PropertyUtil.getNexSerialNum(), "092")); // 网销（官网）业务保单
		if (requestBodyContentStr.contains("@PRINT_CODE@"))
			requestBodyContentStr = requestBodyContentStr.replace("@PRINT_CODE@", PropertyUtil.getNextPrintCode()); // 印刷号

		Matcher matcher = Pattern.compile("@((RQ|RP).+?-\\w+)@").matcher(requestBodyContentStr); // 原先的\\w+替换为.+?，因为\w匹配字母或数字或下划线或汉字，而.匹配除换行符以外的任意字符，另外+?为懒惰匹配(重复1次或更多次但尽可能少重复)
		// 正则查找和替换保单号、保费等字段
		while (matcher.find()) {
			String matcherGroup = matcher.group(1);
			if (requestBodyContentStr.contains("@" + matcherGroup + "@"))
				requestBodyContentStr = requestBodyContentStr.replace("@" + matcherGroup + "@", getElementValue(matcherGroup));
		}
		transXmlMap.put("RQ" + transType, requestBodyContentStr);
		return requestBodyContentStr;
	}

	@Override
	public void setDateOffSet(int dateOffset) {
		this.dateOffSet = dateOffset;
	}

	@Override
	public void setCurrentDate(String currentDateStr) {
		try {
			if (currentDateStr != null && !currentDateStr.trim().equals("")) {
				DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
				Calendar settingCalendar = Calendar.getInstance();
				Calendar currentCalendar = Calendar.getInstance();
				settingCalendar.setTime(dateFormat.parse(currentDateStr));
				currentCalendar.setTime(dateFormat.parse(dateFormat.format(currentCalendar.getTime())));
				dateOffSet = (int) ((settingCalendar.getTimeInMillis() - currentCalendar.getTimeInMillis()) / (1000 * 60 * 60 * 24));
			}
		} catch (ParseException e) {
			log.error(e.getMessage(), e);
		}
	}

	@Override
	public String getElementValue(String transXmlMapKey) {
		return getElementValue(transXmlMapKey, "");
	}

	@Override
	public String getElementValue(String transXmlMapKey, String defaultValue) {
		return getElementValue(transXmlMap.get(transXmlMapKey.split("-")[0]), transXmlMapKey.split("-")[1], defaultValue);
	}

	private String getElementValue(String xmlString, String elementName, String defaultValue) {
		String elementValue = defaultValue;
		if (xmlString != null && !"".equals(xmlString.trim())) {
			Matcher matcher = Pattern.compile("<" + elementName + ">" + "([^<]*)" + "</" + elementName + ">").matcher(xmlString);
			if (matcher.find())
				elementValue = matcher.group(1);
		}
		return elementValue;
	}

	/** 返回长度为3的字符串数组，第0个为日期时间，第1一个为日期，第2个为时间 */
	protected String[] getDateFormatStr(String transType) {
		return new String[] { "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd", "HH:mm:ss" };
	}

	@Override
	public String invoke(Client client, String transType, String requestBodyContentStr) throws Exception {
		String resultStr = null;
		Object results[] = client.invoke(getOperationName(), getClientCode(), transType, requestBodyContentStr);
		if (results != null)
			for (Object result : results)
				resultStr += result;
		transXmlMap.put("RP" + transType, resultStr);
		return resultStr.toString();
	}

	protected abstract String getOperationName();

	protected abstract String getClientCode();
}
